﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Engine2D
{
    public class Camera
    {
        public Vector3 Position { get; set; }
        public Matrix Rotation { get; set; }
        public float FOV { get; set; }
        public float Near { get; set; }
        public float Far { get; set; }
        public Viewport Viewport { get; set; }

        public float AspectRatio { get { return Viewport.Width / (float)Viewport.Height; } }

        private Matrix mView;
        private Matrix mProjection;

        public Matrix View { get { return mView; } }
        public Matrix Projection { get { return mProjection; } }

        private Vector3 mTarget;
        public Vector3 LookAt
        {
            get
            {
                Vector3 diff = mTarget - Position;
                diff.Normalize();
                return diff;
            }
        }

        public Camera()
        {
            Position = new Vector3(0, 0, 0);
            Rotation = Matrix.Identity;
            FOV = MathHelper.ToRadians(60.0f);
            Near = 0.1f;
            Far = 100.0f;
            Viewport = new Viewport(0, 0, 10, 10);

            UpdateMatrices();
        }

        public void Update(GameTime gameTime)
        {
            UpdateMatrices();
        }

        public void UpdateMatrices()
        {
            mTarget = new Vector3(0, 0, -1);
            Vector3 Up = new Vector3(0, 1, 0);

            mTarget = Vector3.Transform(mTarget, Rotation);
            Up = Vector3.Transform(Up, Rotation);

            mView = Matrix.CreateLookAt(Position, mTarget, Up);
            mProjection = Matrix.CreatePerspectiveFieldOfView(FOV, AspectRatio, Near, Far);
        }

        public Ray GetPickingRay(Vector2 screenPos)
        {
            Vector3 near = new Vector3(screenPos.X, screenPos.Y, 0);
            Vector3 far = new Vector3(screenPos.X, screenPos.Y, 1);
            near = Viewport.Unproject(near, Projection, View, Matrix.Identity);
            far = Viewport.Unproject(far, Projection, View, Matrix.Identity);
            Vector3 dir = (far - near);
            dir.Normalize();
            return new Ray(near, dir);
        }
    }
}
